home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 526-550 / disk_535 / keymacro / keymacro.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  26KB  |  1,307 lines

  1. /****************************************************************************
  2. *
  3. *    KeyMacro.c ------------    KeyMacro main process.
  4. *
  5. *    Author ----------------    Olaf Barthel, MXM
  6. *                Brabeckstrasse 35
  7. *                D-3000 Hannover 71
  8. *
  9. *    KeyMacro  ©  Copyright  1990  by  MXM;  Executable  program,
  10. *    documentation  and  source  code are shareware.  If you like
  11. *    this  program  a  small donation will entitle you to receive
  12. *    updates and new programs from MXM.
  13. *
  14. ****************************************************************************/
  15.  
  16.     /* Buffered IO include. */
  17.  
  18. #include "MRArpFile.h"
  19.  
  20.     /* Function prototypes. */
  21.  
  22. VOID            SimpleRequest(UBYTE *Args,...);
  23. VOID            EraseGadget(struct RastPort *RPort,struct Gadget *Gadget,LONG Colour);
  24. BYTE            PopRequest(struct Window *pr_ParentWindow,UBYTE *pr_TitleText,UBYTE *pr_BodyText,UBYTE *pr_PosText,UBYTE *pr_NegText,BYTE pr_Default);
  25.  
  26. UBYTE *            GetToken(UBYTE *s,LONG *start);
  27. struct MacroKey *    AddMacroKey(struct MacroKey *MacroKey);
  28. BYTE            Interprete(UBYTE *String,LONG Line);
  29. BYTE            UpdateList(UBYTE *Name);
  30. BYTE            GetDefaultKeyMap(VOID);
  31. BYTE            UStrCmp(UBYTE *a,UBYTE *b);
  32.  
  33. VOID *            SendMacroMsg(struct MacroMessage *scm_Msg,struct MsgPort *scm_Port);
  34. VOID *            AllocRem(LONG ByteSize,LONG Requirements);
  35. VOID *            FreeRem(LONG *MemoryBlock);
  36. ULONG            KeyInvert(UBYTE AnsiKey,struct InputEvent *Event,struct KeyMap *KeyMap,BYTE Depth);
  37.  
  38. VOID            main(int argc,UBYTE **argv);
  39.  
  40.     /* The Arp CLI-Interface data. */
  41.  
  42. UBYTE *CLI_Template    = "Startup,Q=Quit/s,D=Delay/k,P=Priority/k,I=Info/s";
  43. UBYTE *CLI_Help        = "\nUsage: \33[1mKeyMacro\33[0m <Startup File> [Quit] [Delay <Microseconds>]\n                               [Priority <Input handler priority>] [Info]\n";
  44.  
  45. enum { ARG_STARTUP = 1, ARG_QUIT, ARG_DELAY, ARG_PRI, ARG_INFO };
  46.  
  47.     /* Easy macro. */
  48.  
  49. #define From_CLI    (ThatsMe -> pr_CLI)
  50.  
  51.     /* Global and shared data structures. */
  52.  
  53. extern struct ExecBase        *SysBase;
  54. extern struct IntuitionBase    *IntuitionBase;
  55. extern struct GfxBase        *GfxBase;
  56. struct MSeg            *MSeg;
  57. struct MacroKey            *KeyList;
  58.  
  59.     /* We use this list to identify the non-ascii keys. */
  60.  
  61. struct KeyAlias KeyTab[22] =
  62. {
  63.     {"TAB",        0x42},
  64.     {"ESC",        0x45},
  65.     {"SPACE",    0x40},
  66.     {"RETURN",    0x44},
  67.     {"ENTER",    0x43},
  68.     {"DEL",        0x46},
  69.     {"BACKSPACE",    0x41},
  70.     {"HELP",    0x5F},
  71.     {"LEFT",    0x4F},
  72.     {"RIGHT",    0x4E},
  73.     {"UP",        0x4C},
  74.     {"DOWN",    0x4D},
  75.  
  76.     {"F1",        0x50},
  77.     {"F2",        0x51},
  78.     {"F3",        0x52},
  79.     {"F4",        0x53},
  80.     {"F5",        0x54},
  81.     {"F6",        0x55},
  82.     {"F7",        0x56},
  83.     {"F8",        0x57},
  84.     {"F9",        0x58},
  85.     {"F10",        0x59}
  86. };
  87.  
  88.     /* These are the qualifiers. */
  89.  
  90. struct KeyAlias QualifierTab[9] =
  91. {
  92.     {"NONE",    0},
  93.     {"CTRL",    IEQUALIFIER_CONTROL},
  94.     {"NUMPAD",    IEQUALIFIER_NUMERICPAD},
  95.     {"LSHIFT",    IEQUALIFIER_LSHIFT},
  96.     {"RSHIFT",    IEQUALIFIER_RSHIFT},
  97.     {"LALT",    IEQUALIFIER_LALT},
  98.     {"RALT",    IEQUALIFIER_RALT},
  99.     {"LAMIGA",    IEQUALIFIER_LCOMMAND},
  100.     {"RAMIGA",    IEQUALIFIER_RCOMMAND}
  101. };
  102.  
  103. LONG __stdargs
  104. CXBRK(VOID)
  105. {
  106.     return(0);
  107. }
  108.  
  109. VOID
  110. SimpleRequest(UBYTE *Args,...)
  111. {
  112.     UBYTE     String[512];
  113.     va_list     VarArgs;
  114.  
  115.     va_start(VarArgs,Args);
  116.     ArpVSPrintf(String,Args,VarArgs);
  117.  
  118.     PopRequest(NULL,(UBYTE *)"KeyMacro Request",(UBYTE *)String,NULL,NULL,FALSE);
  119.  
  120.     va_end(VarArgs);
  121. }
  122.  
  123. VOID
  124. EraseGadget(struct RastPort *RPort,struct Gadget *Gadget,LONG Colour)
  125. {
  126.     BYTE FgPen = RPort -> FgPen;
  127.  
  128.     SetAPen(RPort,Colour);
  129.     RectFill(RPort,Gadget -> LeftEdge,Gadget -> TopEdge,Gadget -> LeftEdge + Gadget -> Width - 1,Gadget -> TopEdge + Gadget -> Height - 1);
  130.     SetAPen(RPort,FgPen);
  131. }
  132.  
  133. VOID
  134. CalcDimensions(UBYTE *cd_String,LONG *cd_Width,LONG *cd_Height,LONG cd_MaxWidth)
  135. {
  136.     LONG i,cd_InLine = 0,cd_NumLines = 0;
  137.  
  138.     *cd_Width = *cd_Height = 0;
  139.  
  140.     for(i = 0 ; i < strlen((UBYTE *)cd_String) ; i++)
  141.     {
  142.         if(cd_String[i] == '\n' || cd_InLine == cd_MaxWidth)
  143.         {
  144.             if(cd_InLine > *cd_Width)
  145.                 *cd_Width = cd_InLine;
  146.  
  147.             cd_NumLines++;
  148.             cd_InLine = 0;
  149.  
  150.             continue;
  151.         }
  152.  
  153.         if(cd_String[i] == '\33')
  154.         {
  155.             while(cd_String[i] != 'm' && cd_String[i] != 'w' && i < strlen((UBYTE *)cd_String))
  156.                 i++;
  157.  
  158.             if(i >= strlen((UBYTE *)cd_String))
  159.                 i = strlen((UBYTE *)cd_String) - 1;
  160.  
  161.             continue;
  162.         }
  163.  
  164.         if(cd_String[i] < ' ')
  165.             continue;
  166.  
  167.         cd_InLine++;
  168.     }
  169.  
  170.     *cd_Height = cd_NumLines;
  171.  
  172.     if(cd_InLine > *cd_Width)
  173.         *cd_Width = cd_InLine;
  174. }
  175.  
  176. BYTE
  177. WriteConsole(struct Window *wc_Window,UBYTE *wc_String)
  178. {
  179.     struct IOStdReq    *wc_ConWrite;
  180.     struct MsgPort    *wc_ConPort;
  181.  
  182.     BYTE wc_Success = FALSE;
  183.  
  184.     if(wc_ConPort = (struct MsgPort *)CreatePort(NULL,0))
  185.     {
  186.         if(wc_ConWrite = (struct IOStdReq *)CreateStdIO(wc_ConPort))
  187.         {
  188.             wc_ConWrite -> io_Data        = (APTR)wc_Window;
  189.             wc_ConWrite -> io_Length    = sizeof(struct Window);
  190.  
  191.             if(!OpenDevice("console.device",0,wc_ConWrite,0))
  192.             {
  193.                 wc_ConWrite -> io_Command    = CMD_WRITE;
  194.                 wc_ConWrite -> io_Data        = (APTR)"\2330 p";
  195.                 wc_ConWrite -> io_Length    = -1;
  196.  
  197.                 DoIO(wc_ConWrite);
  198.  
  199.                 wc_ConWrite -> io_Data        = (APTR)wc_String;
  200.                 wc_ConWrite -> io_Length    = -1;
  201.  
  202.                 DoIO(wc_ConWrite);
  203.  
  204.                 wc_Success = TRUE;
  205.  
  206.                 CloseDevice(wc_ConWrite);
  207.             }
  208.  
  209.             DeleteStdIO(wc_ConWrite);
  210.         }
  211.  
  212.         DeletePort(wc_ConPort);
  213.     }
  214.  
  215.     return(wc_Success);
  216. }
  217.  
  218. BYTE
  219. PopRequest(struct Window *pr_ParentWindow,UBYTE *pr_TitleText,UBYTE *pr_BodyText,UBYTE *pr_PosText,UBYTE *pr_NegText,BYTE pr_Default)
  220. {
  221.     STATIC struct NewWindow pr_StaticNewWindow =
  222.     {
  223.         0,0,
  224.         0,1,
  225.         0,1,
  226.         VANILLAKEY | MOUSEBUTTONS | GADGETUP | CLOSEWINDOW | CLOSEWINDOW,
  227.         RMBTRAP | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE,
  228.         (struct Gadget *)NULL,
  229.         (struct Image *)NULL,
  230.         (STRPTR)NULL,
  231.         (struct Screen *)NULL,
  232.         (struct BitMap *)NULL,
  233.         0,0,
  234.         0,0,
  235.         WBENCHSCREEN
  236.     };
  237.  
  238.     STATIC struct Gadget pr_StaticGadget =
  239.     {
  240.         (struct Gadget *)NULL,
  241.         0,0,
  242.         0,0,
  243.         GADGHBOX,
  244.         RELVERIFY | GADGIMMEDIATE,
  245.         BOOLGADGET,
  246.         (APTR)NULL,
  247.         (APTR)NULL,
  248.         (struct IntuiText *)NULL,
  249.         NULL,
  250.         (APTR)NULL,
  251.         0,
  252.         (APTR)NULL
  253.     };
  254.  
  255.     STATIC struct TextAttr pr_TextAttr =
  256.     {
  257.         (UBYTE *)"topaz.font",
  258.         8,
  259.         FS_NORMAL,
  260.         FPF_ROMFONT
  261.     };
  262.  
  263.     struct NewWindow    *pr_NewWindow;
  264.     struct Window        *pr_Window;
  265.     struct IntuiMessage    *pr_IMsg;
  266.     struct Gadget        *pr_PosGadget = NULL,*pr_NegGadget = NULL,*pr_TempGadget;
  267.  
  268.     struct Screen         pr_Screen,*pr_FrontScreen;
  269.     struct TextFont        *pr_TextFont;
  270.  
  271.     LONG             pr_Width,pr_Height;
  272.     BYTE             pr_Result = FALSE;
  273.     ULONG             pr_IntuiLock;
  274.  
  275.     if(!pr_BodyText)
  276.         return(pr_Result);
  277.  
  278.     if(!(pr_NewWindow = (struct NewWindow *)AllocMem(sizeof(struct NewWindow),MEMF_PUBLIC)))
  279.         return(pr_Result);
  280.  
  281.     CopyMem(&pr_StaticNewWindow,pr_NewWindow,sizeof(struct NewWindow));
  282.  
  283.     pr_IntuiLock = LockIBase(NULL);
  284.  
  285.     pr_FrontScreen = IntuitionBase -> FirstScreen;
  286.  
  287.     UnlockIBase(pr_IntuiLock);
  288.  
  289.     if(pr_ParentWindow)
  290.     {
  291.         pr_NewWindow -> Type    = CUSTOMSCREEN;
  292.         pr_NewWindow -> Screen    = pr_ParentWindow -> WScreen;
  293.     }
  294.     else
  295.         OpenWorkBench();
  296.  
  297.     if(!GetScreenData(&pr_Screen,sizeof(struct Screen),pr_NewWindow -> Type,pr_NewWindow -> Screen))
  298.     {
  299.         FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  300.         return(pr_Result);
  301.     }
  302.  
  303.     CalcDimensions(pr_BodyText,&pr_Width,&pr_Height,(pr_Screen . Width - 6) / 8);
  304.  
  305.     if(pr_Height > (pr_Screen . Height - 15 - 13) / 8)
  306.     {
  307.         FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  308.         return(pr_Result);
  309.     }
  310.  
  311.     pr_NewWindow -> Width    = pr_Width * 8 + 6 + 4;
  312.     pr_NewWindow -> Height    = pr_Height * 8 + GfxBase -> DefaultFont -> tf_YSize + 7 + 19 + 2;
  313.  
  314.     if(pr_TitleText)
  315.         pr_NewWindow -> Title = pr_TitleText;
  316.     else
  317.         pr_NewWindow -> Title = (UBYTE *)"System Request";
  318.  
  319.     if(!pr_PosText && !pr_NegText)
  320.         pr_NegText = (UBYTE *)"Continue?";
  321.  
  322.     if(pr_PosText)
  323.     {
  324.         if(!(pr_PosGadget = (struct Gadget *)AllocMem(sizeof(struct Gadget),MEMF_PUBLIC)))
  325.         {
  326.             FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  327.             return(pr_Result);
  328.         }
  329.  
  330.         CopyMem(&pr_StaticGadget,pr_PosGadget,sizeof(struct Gadget));
  331.  
  332.         pr_PosGadget -> Width    = 8 * strlen((UBYTE *)pr_PosText) + 4;
  333.         pr_PosGadget -> Height    = 8 + 2;
  334.  
  335.         pr_PosGadget -> LeftEdge= 3 + 2 + 3;
  336.         pr_PosGadget -> TopEdge    = pr_NewWindow -> Height - 13 - 1;
  337.     }
  338.  
  339.     if(pr_NegText)
  340.     {
  341.         if(!(pr_NegGadget = (struct Gadget *)AllocMem(sizeof(struct Gadget),MEMF_PUBLIC)))
  342.         {
  343.             FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  344.  
  345.             if(pr_PosGadget)
  346.                 FreeMem(pr_PosGadget,sizeof(struct Gadget));
  347.  
  348.             return(pr_Result);
  349.         }
  350.  
  351.         CopyMem(&pr_StaticGadget,pr_NegGadget,sizeof(struct Gadget));
  352.  
  353.         pr_NegGadget -> Width    = 8 * strlen((UBYTE *)pr_NegText) + 4;
  354.         pr_NegGadget -> Height    = 8 + 2;
  355.  
  356.         pr_Width = pr_NegGadget -> Width + 6 + 4 + 6;
  357.  
  358.         if(pr_PosGadget)
  359.             pr_Width += (pr_PosGadget -> Width + 12);
  360.  
  361.         if(pr_NewWindow -> Width < pr_Width)
  362.             pr_NewWindow -> Width = pr_Width;
  363.  
  364.         pr_NegGadget -> LeftEdge= pr_NewWindow -> Width - pr_NegGadget -> Width - 3 - 2 - 3;
  365.         pr_NegGadget -> TopEdge    = pr_NewWindow -> Height - 13 - 1;
  366.  
  367.         pr_NegGadget -> GadgetID= 1;
  368.     }
  369.  
  370.     if(!pr_NegGadget && pr_NewWindow -> Width < pr_PosGadget -> Width + 6 + 4 + 6)
  371.         pr_NewWindow -> Width = pr_PosGadget -> Width + 6 + 4 + 6;
  372.  
  373.     if(pr_Default && !pr_PosGadget)
  374.         pr_Default = FALSE;
  375.  
  376.     if(!pr_Default && !pr_NegGadget)
  377.         pr_Default = TRUE;
  378.  
  379.     if(pr_Default)
  380.         pr_TempGadget = pr_PosGadget;
  381.     else
  382.         pr_TempGadget = pr_NegGadget;
  383.  
  384.     pr_NewWindow -> LeftEdge= pr_Screen . MouseX - (pr_TempGadget -> LeftEdge + pr_TempGadget -> Width / 2);
  385.     pr_NewWindow -> TopEdge    = pr_Screen . MouseY - (pr_TempGadget -> TopEdge + pr_TempGadget -> Height / 2);
  386.  
  387.     while(pr_NewWindow -> LeftEdge < 0)
  388.         pr_NewWindow -> LeftEdge++;
  389.  
  390.     while(pr_NewWindow -> TopEdge < 0)
  391.         pr_NewWindow -> TopEdge++;
  392.  
  393.     while(pr_NewWindow -> LeftEdge + pr_NewWindow -> Width >= pr_Screen . Width)
  394.         pr_NewWindow -> LeftEdge--;
  395.  
  396.     while(pr_NewWindow -> TopEdge + pr_NewWindow -> Height >= pr_Screen . Height)
  397.         pr_NewWindow -> TopEdge--;
  398.  
  399.     if(!(pr_TextFont = (struct TextFont *)OpenFont(&pr_TextAttr)))
  400.     {
  401.         if(pr_PosGadget)
  402.             FreeMem(pr_PosGadget,sizeof(struct Gadget));
  403.  
  404.         if(pr_NegGadget)
  405.             FreeMem(pr_NegGadget,sizeof(struct Gadget));
  406.  
  407.         FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  408.  
  409.         return(pr_Result);
  410.     }
  411.  
  412.     if(!(pr_Window = (struct Window *)OpenWindow(pr_NewWindow)))
  413.     {
  414.         CloseFont(pr_TextFont);
  415.  
  416.         if(pr_PosGadget)
  417.             FreeMem(pr_PosGadget,sizeof(struct Gadget));
  418.  
  419.         if(pr_NegGadget)
  420.             FreeMem(pr_NegGadget,sizeof(struct Gadget));
  421.  
  422.         FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  423.  
  424.         return(pr_Result);
  425.     }
  426.  
  427.     SetFont(pr_Window -> RPort,pr_TextFont);
  428.  
  429.     SetAPen(pr_Window -> RPort,3);
  430.     SetBPen(pr_Window -> RPort,2);
  431.     SetDrMd(pr_Window -> RPort,JAM2);
  432.  
  433.     WriteConsole(pr_Window,pr_BodyText);
  434.  
  435.     if(pr_PosGadget)
  436.     {
  437.         AddGadget(pr_Window,pr_PosGadget,1);
  438.  
  439.         EraseGadget(pr_Window -> RPort,pr_PosGadget,2);
  440.  
  441.         Move(pr_Window -> RPort,pr_PosGadget -> LeftEdge + 2,pr_PosGadget -> TopEdge + 1 + pr_TextFont -> tf_Baseline);
  442.         Text(pr_Window -> RPort,(UBYTE *)pr_PosText,strlen((UBYTE *)pr_PosText));
  443.     }
  444.  
  445.     if(pr_NegGadget)
  446.     {
  447.         AddGadget(pr_Window,pr_NegGadget,1);
  448.  
  449.         EraseGadget(pr_Window -> RPort,pr_NegGadget,2);
  450.  
  451.         Move(pr_Window -> RPort,pr_NegGadget -> LeftEdge + 2,pr_NegGadget -> TopEdge + 1 + pr_TextFont -> tf_Baseline);
  452.         Text(pr_Window -> RPort,(UBYTE *)pr_NegText,strlen((UBYTE *)pr_NegText));
  453.     }
  454.  
  455.     MoveScreen(pr_Window -> WScreen,0,- pr_Window -> WScreen -> TopEdge);
  456.     ScreenToFront(pr_Window -> WScreen);
  457.     ActivateWindow(pr_Window);
  458.  
  459. Skip1:    FOREVER
  460.     {
  461.         ULONG pr_Class,pr_Code;
  462.         struct Gadget *pr_Gadget;
  463.  
  464.         WaitPort(pr_Window -> UserPort);
  465.  
  466.         if(pr_IMsg = (struct IntuiMessage *)GetMsg(pr_Window -> UserPort))
  467.         {
  468.             pr_Class    = pr_IMsg -> Class;
  469.             pr_Code        = pr_IMsg -> Code;
  470.             pr_Gadget    = (struct Gadget *)pr_IMsg -> IAddress;
  471.  
  472.             if(pr_Class == VANILLAKEY)
  473.                 pr_Code = toupper(pr_Code);
  474.  
  475.             ReplyMsg(pr_IMsg);
  476.  
  477.             if(pr_Class == GADGETUP)
  478.             {
  479.                 if(pr_Gadget -> GadgetID == 0)
  480.                     pr_Result = TRUE;
  481.  
  482.                 break;
  483.             }
  484.  
  485.             if(pr_Class == CLOSEWINDOW)
  486.                 break;
  487.  
  488.             if(pr_Class == VANILLAKEY)
  489.             {
  490.                 pr_Code = toupper(pr_Code);
  491.  
  492.                 if((pr_Code == 'Y' || pr_Code == 'J' || pr_Code == 'V' || pr_Code == 'C' || pr_Code == 'R' || pr_Code == '\r') && pr_PosText)
  493.                 {
  494.                     pr_Result = TRUE;
  495.                     break;
  496.                 }
  497.  
  498.                 if((pr_Code == 'N' || pr_Code == 'Q' || pr_Code == 'B' || pr_Code == '\33') && pr_NegText)
  499.                     break;
  500.  
  501.                 continue;
  502.             }
  503.         }
  504.     }
  505.  
  506.     CloseFont(pr_TextFont);
  507.  
  508.     if(pr_PosGadget)
  509.     {
  510.         RemoveGadget(pr_Window,pr_PosGadget);
  511.         FreeMem(pr_PosGadget,sizeof(struct Gadget));
  512.     }
  513.  
  514.     if(pr_NegGadget)
  515.     {
  516.         RemoveGadget(pr_Window,pr_NegGadget);
  517.         FreeMem(pr_NegGadget,sizeof(struct Gadget));
  518.     }
  519.  
  520.     FreeMem(pr_NewWindow,sizeof(struct NewWindow));
  521.  
  522.     pr_IntuiLock = LockIBase(NULL);
  523.  
  524.     if(pr_FrontScreen == IntuitionBase -> FirstScreen)
  525.         pr_FrontScreen = NULL;
  526.  
  527.     UnlockIBase(pr_IntuiLock);
  528.  
  529.     if(pr_FrontScreen)
  530.         ScreenToFront(pr_FrontScreen);
  531.  
  532.     CloseWindow(pr_Window);
  533.  
  534.     return(pr_Result);
  535. }
  536.  
  537.     /* UStrCmp():
  538.      *
  539.      *    strcmp function which ignores case.
  540.      */
  541.  
  542. BYTE
  543. UStrCmp(UBYTE *a,UBYTE *b)
  544. {
  545.     for( ; ToUpper(*a) == ToUpper(*b) ; a++, b++)
  546.     {
  547.         if(!(*a))
  548.             return(0);
  549.     }
  550.  
  551.     return(1);
  552. }
  553.  
  554.     /* GetToken(s,start):
  555.      *
  556.      *    Parse a string and split it into single tokens.
  557.      */
  558.  
  559. UBYTE *
  560. GetToken(UBYTE *s,LONG *start)
  561. {
  562.     static UBYTE    buffer[256];
  563.     LONG        i,end = 0,quote = FALSE,maxlen = strlen(s);
  564.     UBYTE        t;
  565.  
  566.     if(maxlen > 255)
  567.         maxlen = 255;
  568.  
  569.     if(*start > strlen(s) - 1 || !strlen(s) || !s)
  570.         return(NULL);
  571.  
  572.     for(i = *start ; i <= maxlen ; i++)
  573.     {
  574.         if(!end && (s[i] == ' ' || s[i] == '\t'))
  575.         {
  576.             while((s[i] == ' ' || s[i] == '\t') && i < maxlen)
  577.             {
  578.                 i++;
  579.                 (*start)++;
  580.             }
  581.         }
  582.  
  583.         t = s[i];
  584.  
  585.         if(!end && t == '+')
  586.         {
  587.             (*start)++;
  588.             continue;
  589.         }
  590.  
  591.         if(!end && t == '=')
  592.         {
  593.             strcpy(buffer,"=");
  594.             (*start)++;
  595.  
  596.             return(buffer);
  597.         }
  598.  
  599.         if(s[i] == '\\' && s[i + 1] == '\"')
  600.         {
  601.             i += 2;
  602.  
  603.             end = i - *start + 1;
  604.  
  605.             t = s[i];
  606.         }
  607.  
  608.         if(t == '\"' && !quote)
  609.         {
  610.             quote = TRUE;
  611.  
  612.             (*start)++;
  613.  
  614.             end++;
  615.  
  616.             continue;
  617.         }
  618.  
  619.         if((t == '+' || t == '=' || t == ' ' || t == '\t' || t == ';') && quote)
  620.         {
  621.             end++;
  622.             continue;
  623.         }
  624.  
  625.         if((t == '+' || t == '\n' || t == '=' || t == ' ' || t == 0) || (t == '\"' && quote) || (t == ';' && !quote))
  626.         {
  627.             if(t == ';' && !end)
  628.                 return(NULL);
  629.  
  630.             if(t == '\"')
  631.             {
  632.                 strncpy(buffer,s + *start,end - 1);
  633.                 buffer[end - 1] = 0;
  634.             }
  635.             else
  636.             {
  637.                 strncpy(buffer,s + *start,end);
  638.                 buffer[end] = 0;
  639.             }
  640.  
  641.             (*start) += end;
  642.  
  643.             return(buffer);
  644.         }
  645.  
  646.         end++;
  647.     }
  648.  
  649.     return(NULL);
  650. }
  651.  
  652.     /* AddMacroKey(MacroKey):
  653.      *
  654.      *    Add a macro key to the big list.
  655.      */
  656.  
  657. struct MacroKey    *
  658. AddMacroKey(struct MacroKey *TheKey)
  659. {
  660.     struct MacroKey *MacroKey;
  661.  
  662.     if(MacroKey = (struct MacroKey *)AllocRem(sizeof(struct MacroKey),MEMF_PUBLIC|MEMF_CLEAR))
  663.     {
  664.         ObtainSemaphore(&MSeg -> MacroSemaphore);
  665.  
  666.         if(MSeg -> NumMacros == MSeg -> MaxMacros)
  667.         {
  668.             struct MacroKey **MacroList;
  669.  
  670.             if(MacroList = (struct MacroKey **)AllocRem((MSeg -> MaxMacros + 10) * sizeof(struct MacroKey *),MEMF_PUBLIC|MEMF_CLEAR))
  671.             {
  672.                 if(MSeg -> MacroList)
  673.                 {
  674.                     LONG i;
  675.  
  676.                     for(i = 0 ; i < MSeg -> NumMacros ; i++)
  677.                         MacroList[i] = MSeg -> MacroList[i];
  678.  
  679.                     FreeRem(MSeg -> MacroList);
  680.                 }
  681.  
  682.                 MSeg -> MacroList = MacroList;
  683.  
  684.                 MSeg -> MaxMacros += 10;
  685.             }
  686.             else
  687.             {
  688.                 FreeRem(MacroKey);
  689.  
  690.                 return(NULL);
  691.             }
  692.         }
  693.  
  694.         MSeg -> MacroList[MSeg -> NumMacros++] = MacroKey;
  695.  
  696.         CopyMem(TheKey,MacroKey,sizeof(struct MacroKey));
  697.  
  698.         ReleaseSemaphore(&MSeg -> MacroSemaphore);
  699.  
  700.         return(MacroKey);
  701.     }
  702.  
  703.     return(NULL);
  704. }
  705.  
  706.     /* Interprete(String,Line):
  707.      *
  708.      *    Interprete a command line from the config file.
  709.      */
  710.  
  711. BYTE
  712. Interprete(UBYTE *String,LONG Line)
  713. {
  714.     ULONG             Qualifier = 0;
  715.     ULONG             Code = -1;
  716.     struct InputEvent     FakeEvent;
  717.     struct MacroKey         NewKey;
  718.  
  719.     LONG             Start = 0,Key = FALSE,i,KeyCount = 0;
  720.     volatile LONG         QuitLoop;
  721.     UBYTE            *Token,*CommandString,*WindowName = NULL,Recognized = FALSE;
  722.  
  723.     UBYTE             KeyBuff1[40],KeyBuff2[40];
  724.  
  725.     if(String[strlen(String) - 1] == '\n')
  726.         String[strlen(String) - 1] = 0;
  727.  
  728.     if(Token = GetToken(String,&Start))
  729.     {
  730.         if(!UStrCmp("KEY",Token))
  731.             Key = TRUE;
  732.  
  733.         if(UStrCmp("COMMAND",Token) && !Key)
  734.         {
  735.             SimpleRequest("Line %ld: Unknown keyword:\n\n'%s'",Line,String);
  736.             return(FALSE);
  737.         }
  738.     }
  739.     else
  740.         return(TRUE);
  741.  
  742.     FOREVER
  743.     {
  744.         if(Token = GetToken(String,&Start))
  745.         {
  746.             QuitLoop = TRUE;
  747.  
  748.             for(i = 0 ; i < 9 ; i++)
  749.             {
  750.                 if(!UStrCmp(QualifierTab[i] . ka_Name,Token))
  751.                 {
  752.                     Recognized = TRUE;
  753.                     QuitLoop = FALSE;
  754.  
  755.                     Qualifier |= QualifierTab[i] . ka_Key;
  756.                 }
  757.             }
  758.         }
  759.         else
  760.             break;
  761.  
  762.         if(QuitLoop)
  763.             break;
  764.     }
  765.  
  766.     if(!Recognized)
  767.     {
  768.         SimpleRequest("Line %ld: Didn't recognize qualifier:\n\n'%s'",Line,String);
  769.         return(FALSE);
  770.     }
  771.  
  772.     if(Token)
  773.         goto JumpIn;
  774.  
  775.     if(Token = GetToken(String,&Start))
  776.     {
  777. JumpIn:        for(i = 0 ; i < 22 ; i++)
  778.         {
  779.             if(!UStrCmp(KeyTab[i] . ka_Name,Token))
  780.             {
  781.                 Code = KeyTab[i] . ka_Key;
  782.                 goto Next;
  783.             }
  784.         }
  785.  
  786.         if(KeyInvert(Token[0],&FakeEvent,MSeg -> DefaultKeyMap,1))
  787.             Code = FakeEvent . ie_Code;
  788.     }
  789.  
  790.     if(Code == -1)
  791.     {
  792.         SimpleRequest("Line %ld: Didn't recognize key:\n\n'%s'",Line,String);
  793.         return(FALSE);
  794.     }
  795.  
  796. Next:    FOREVER
  797.     {
  798.         if(Token = GetToken(String,&Start))
  799.         {
  800.             if(!UStrCmp("=",Token))
  801.                 break;
  802.         }
  803.         else
  804.         {
  805.             SimpleRequest("Line %ld: Statement '=' missing:\n\n'%s'",Line,String);
  806.             return(FALSE);
  807.         }
  808.     }
  809.  
  810.     if(Token = GetToken(String,&Start))
  811.         strcpy(KeyBuff1,Token);
  812.     else
  813.     {
  814.         SimpleRequest("Line %ld: Didn't find macro:\n\n'%s'",Line,String);
  815.         return(FALSE);
  816.     }
  817.  
  818.     if(Key)
  819.         goto AddIt;
  820.  
  821.     if(!(Token = GetToken(String,&Start)))
  822.         goto AddIt;
  823.  
  824.     if(UStrCmp("WINDOW",Token))
  825.     {
  826.         SimpleRequest("Line %ld: Didn't recognize 'WINDOW' statement:\n\n'%s'",Line,String);
  827.         return(FALSE);
  828.     }
  829.  
  830.     if(!(Token = GetToken(String,&Start)))
  831.     {
  832.         SimpleRequest("Line %ld: Didn't find window title:\n\n'%s'",Line,String);
  833.         return(FALSE);
  834.     }
  835.  
  836.     if(!(WindowName = (UBYTE *)AllocRem(strlen(Token) + 1,MEMF_PUBLIC)))
  837.     {
  838.         SimpleRequest("Can't allocate memory chunk!");
  839.         return(FALSE);
  840.     }
  841.  
  842.     strcpy(WindowName,Token);
  843.  
  844. AddIt:    for(i = 0 ; i < strlen(KeyBuff1) ; i++)
  845.     {
  846.         UBYTE c;
  847.  
  848.         if(KeyBuff1[i] != '\\')
  849.         {
  850.             KeyBuff2[KeyCount++] = KeyBuff1[i];
  851.             continue;
  852.         }
  853.  
  854.         if(i == strlen(KeyBuff1) - 1)
  855.             break;
  856.  
  857.         i++;
  858.  
  859.         c = 0;
  860.  
  861.         switch(ToUpper(KeyBuff1[i]))
  862.         {
  863.             case 'U':    c = KC_CURSORUP;
  864.                     break;
  865.  
  866.             case 'D':    c = KC_CURSORDOWN;
  867.                     break;
  868.  
  869.             case 'L':    c = KC_CURSORLEFT;
  870.                     break;
  871.  
  872.             case 'R':    c = KC_CURSORRIGHT;
  873.                     break;
  874.  
  875.             case 'H':    c = KC_HELP;
  876.                     break;
  877.  
  878.             case 'B':    c = 8;
  879.                     break;
  880.  
  881.             case 'E':    c = 127;
  882.                     break;
  883.  
  884.             case 'F':    if(i == strlen(KeyBuff1) - 1)
  885.                         break;
  886.  
  887.                     i++;
  888.  
  889.                     if(!isdigit(KeyBuff1[i]))
  890.                         break;
  891.  
  892.                     if(!KeyBuff1[i] == '1')
  893.                     {
  894.                         c = KC_FKEY1 + KeyBuff1[i] - '1';
  895.                         break;
  896.                     }
  897.  
  898.                     if(i == strlen(KeyBuff1) - 1)
  899.                         break;
  900.  
  901.                     i++;
  902.  
  903.                     if(!isdigit(KeyBuff1[i]))
  904.                     {
  905.                         c = KC_FKEY1;
  906.                         break;
  907.                     }
  908.  
  909.                     if(KeyBuff1[i] != '0')
  910.                         break;
  911.  
  912.                     c = KC_FKEY10;
  913.                     break;
  914.  
  915.             case 'N':    c = '\n';
  916.                     break;
  917.  
  918.             case '\\':    c = '\\';
  919.                     break;
  920.  
  921.             default:    c = KeyBuff1[i];
  922.  
  923.                     break;
  924.         }
  925.  
  926.         if(c)
  927.             KeyBuff2[KeyCount++] = c;
  928.     }
  929.  
  930.     KeyBuff2[KeyCount] = 0;
  931.  
  932.     if(!(CommandString = (UBYTE *)AllocRem(strlen(KeyBuff2) + 1,MEMF_PUBLIC)))
  933.     {
  934.         SimpleRequest("Can't allocate memory chunk!");
  935.         FreeRem(WindowName);
  936.  
  937.         return(FALSE);
  938.     }
  939.  
  940.     strcpy(CommandString,KeyBuff2);
  941.  
  942.     memset(&NewKey,0,sizeof(struct MacroKey));
  943.  
  944.     NewKey . mk_CommandKey        = Code;
  945.     NewKey . mk_CommandQualifier    = Qualifier;
  946.  
  947.     NewKey . mk_String        = CommandString;
  948.     NewKey . mk_Window        = WindowName;
  949.  
  950.     if(Key)
  951.         NewKey . mk_Type    = MK_WORD;
  952.     else
  953.         NewKey . mk_Type    = MK_COMMAND;
  954.  
  955.     if(AddMacroKey(&NewKey))
  956.         return(TRUE);
  957.  
  958.     SimpleRequest("Line %ld: Key macro table full.",Line);
  959.     return(FALSE);
  960. }
  961.  
  962.     /* UpdateList(Name):
  963.      *
  964.      *    Update the big macro key list.
  965.      */
  966.  
  967. BYTE
  968. UpdateList(UBYTE *Name)
  969. {
  970.     UBYTE         LineBuff[257];
  971.     LONG         LineNum = 1;
  972.     ARPFileHandle    *ConfigFile;
  973.  
  974.     if(!Name)
  975.         Name = "S:KeyMacro.config";
  976.  
  977.     GetDefaultKeyMap();
  978.  
  979.     if(ConfigFile = OpenARPFile(Name,MODE_OLDFILE,976))
  980.     {
  981.         if(MSeg -> MacroList)
  982.         {
  983.             LONG i;
  984.  
  985.             ObtainSemaphore(&MSeg -> MacroSemaphore);
  986.  
  987.             for(i = 0 ; i < MSeg -> NumMacros ; i++)
  988.             {
  989.                 if(MSeg -> MacroList[i])
  990.                 {
  991.                     if(MSeg -> MacroList[i] -> mk_String)
  992.                         FreeRem(MSeg -> MacroList[i] -> mk_String);
  993.  
  994.                     if(MSeg -> MacroList[i] -> mk_Window)
  995.                         FreeRem(MSeg -> MacroList[i] -> mk_Window);
  996.  
  997.                     FreeRem(MSeg -> MacroList[i]);
  998.                 }
  999.             }
  1000.  
  1001.             FreeRem(MSeg -> MacroList);
  1002.  
  1003.             MSeg -> MacroList = NULL;
  1004.  
  1005.             MSeg -> NumMacros = MSeg -> MaxMacros = 0;
  1006.  
  1007.             ReleaseSemaphore(&MSeg -> MacroSemaphore);
  1008.         }
  1009.  
  1010.         while(FGetsARP(LineBuff,256,ConfigFile))
  1011.         {
  1012.             if(!Interprete(LineBuff,LineNum++))
  1013.             {
  1014.                 CloseARPFile(ConfigFile);
  1015.  
  1016.                 return(FALSE);
  1017.             }
  1018.         }
  1019.  
  1020.         CloseARPFile(ConfigFile);
  1021.     }
  1022.     else
  1023.     {
  1024.         SimpleRequest("Couldn't open configuration file!");
  1025.         FreeRem(KeyList);
  1026.  
  1027.         return(FALSE);
  1028.     }
  1029.  
  1030.     return(TRUE);
  1031. }
  1032.  
  1033. BYTE
  1034. GetDefaultKeyMap()
  1035. {
  1036.     struct IOStdReq    *ConsoleRequest;
  1037.     struct MsgPort    *ConsolePort;
  1038.     BYTE         Result = FALSE;
  1039.  
  1040.     if(ConsolePort = CreatePort(NULL,0))
  1041.     {
  1042.         if(ConsoleRequest = CreateStdIO(ConsolePort))
  1043.         {
  1044.             if(!OpenDevice("console.device",CONU_STANDARD,ConsoleRequest,0))
  1045.             {
  1046.                 ConsoleRequest -> io_Command    = CD_ASKDEFAULTKEYMAP;
  1047.                 ConsoleRequest -> io_Length    = sizeof(struct KeyMap);
  1048.                 ConsoleRequest -> io_Data    = (APTR)MSeg -> DefaultKeyMap;
  1049.                 ConsoleRequest -> io_Flags    = IOF_QUICK;
  1050.  
  1051.                 if(!DoIO(ConsoleRequest))
  1052.                     Result = TRUE;
  1053.  
  1054.                 CloseDevice(ConsoleRequest);
  1055.             }
  1056.  
  1057.             DeleteStdIO(ConsoleRequest);
  1058.         }
  1059.  
  1060.         DeletePort(ConsolePort);
  1061.     }
  1062.  
  1063.     return(Result);
  1064. }
  1065.  
  1066.     /* main(argc,argv):
  1067.      *
  1068.      *    The entry point to this program.
  1069.      */
  1070.  
  1071. VOID
  1072. main(int argc,UBYTE **argv)
  1073. {
  1074.     struct Process    *ThatsMe = (struct Process *)SysBase -> ThisTask;
  1075.     UBYTE        *FileName = argv[ARG_STARTUP];
  1076.     LONG         Created = FALSE;
  1077.     LONG         i;
  1078.  
  1079.         /* Started from Workbench? */
  1080.  
  1081.     if(!From_CLI)
  1082.         FileName = NULL;
  1083.  
  1084.         /* Look if handler process is already running. */
  1085.  
  1086.     MSeg = (struct MSeg *)FindPort(PORTNAME);
  1087.  
  1088.         /* Short info? */
  1089.  
  1090.     if(argv[ARG_INFO])
  1091.     {
  1092.         Printf("\n\33[1m\33[33mKeyMacro\33[31m\33[0m the Amiga macro key handler.\n\n");
  1093.  
  1094.         Printf("         This program may be non-commercially\n");
  1095.         Printf("         redistributed!\n\n");
  1096.  
  1097.         Printf("\33[1m\33[33mAuthor\33[31m\33[0m - Olaf Barthel, MXM\n");
  1098.         Printf("         Brabeckstrasse 35\n");
  1099.         Printf("         D-3000 Hannover 71\n\n");
  1100.  
  1101.         Printf("     Federal Republic of Germany.\n\n");
  1102.  
  1103.         exit(RETURN_OK);
  1104.     }
  1105.  
  1106.         /* Remove the handler? */
  1107.  
  1108.     if(argv[ARG_QUIT])
  1109.     {
  1110.         Printf("Removing \33[1m\33[33mKeyMacro\33[31m\33[0m, ");
  1111.  
  1112.         if(!MSeg)
  1113.         {
  1114.             Printf("failed!\a\n");
  1115.  
  1116.             exit(RETURN_OK);
  1117.         }
  1118.  
  1119.         MSeg -> Father = (struct Task *)SysBase -> ThisTask;
  1120.  
  1121.         if(MSeg -> Child)
  1122.         {
  1123.             Signal(MSeg -> Child,SIG_CLOSE);
  1124.  
  1125.             Wait(SIG_CLOSE);
  1126.         }
  1127.  
  1128.         RemPort(&MSeg -> Port);
  1129.  
  1130.         FreeMem(MSeg -> Port . mp_Node . ln_Name,sizeof(PORTNAME));
  1131.  
  1132.         if(MSeg -> Segment)
  1133.             UnLoadSeg(MSeg -> Segment);
  1134.  
  1135.         if(MSeg -> MacroList)
  1136.         {
  1137.             for(i = 0 ; i < MSeg -> NumMacros ; i++)
  1138.             {
  1139.                 if(MSeg -> MacroList[i])
  1140.                 {
  1141.                     if(MSeg -> MacroList[i] -> mk_String)
  1142.                         FreeRem(MSeg -> MacroList[i] -> mk_String);
  1143.  
  1144.                     if(MSeg -> MacroList[i] -> mk_Window)
  1145.                         FreeRem(MSeg -> MacroList[i] -> mk_Window);
  1146.  
  1147.                     FreeRem(MSeg -> MacroList[i]);
  1148.                 }
  1149.             }
  1150.  
  1151.             FreeRem(MSeg -> MacroList);
  1152.         }
  1153.  
  1154.         FreeRem(MSeg -> DefaultKeyMap);
  1155.         FreeRem(MSeg);
  1156.  
  1157.         Printf("OK.\n");
  1158.  
  1159.         exit(RETURN_OK);
  1160.     }
  1161.  
  1162.         /* Allocate the handler data. */
  1163.  
  1164.     if(!MSeg)
  1165.     {
  1166.         if(MSeg = (struct MSeg *)AllocRem(sizeof(struct MSeg),MEMF_PUBLIC | MEMF_CLEAR))
  1167.         {
  1168.             MSeg -> Port . mp_Flags            = PA_IGNORE;
  1169.             MSeg -> Port . mp_Node . ln_Pri        = 0;
  1170.             MSeg -> Port . mp_Node . ln_Type    = NT_MSGPORT;
  1171.             MSeg -> Port . mp_Node . ln_Name    = AllocMem(sizeof(PORTNAME),MEMF_PUBLIC);
  1172.             MSeg -> Child                = NULL;
  1173.             MSeg -> Father                = (struct Task *)SysBase -> ThisTask;
  1174.             MSeg -> SegSize                = sizeof(struct MSeg);
  1175.             MSeg -> RingBack            = SIGBREAKF_CTRL_C;
  1176.             MSeg -> Revision            = REVISION;
  1177.  
  1178.             if(argv[ARG_PRI])
  1179.                 MSeg -> Pri = Atol(argv[ARG_PRI]);
  1180.             else
  1181.                 MSeg -> Pri = 51;
  1182.  
  1183.             NewList(&MSeg -> Port . mp_MsgList);
  1184.  
  1185.             InitSemaphore(&MSeg -> MacroSemaphore);
  1186.  
  1187.             if(From_CLI)
  1188.             {
  1189.                 Printf("\33[1m\33[33mKeyMacro v1.%ld \33[31m\33[0m© Copyright 1989, 1990 by \33[4mMXM\33[0m, All rights reserved.\n",REVISION);
  1190.  
  1191.                 Printf("Installing \33[33m\33[1mKeyMacro\33[0m\33[31m, ");
  1192.             }
  1193.  
  1194.             if(MSeg -> Port . mp_Node . ln_Name)
  1195.                 strcpy(MSeg -> Port . mp_Node . ln_Name,PORTNAME);
  1196.             else
  1197.             {
  1198. Failed:                FreeRem(MSeg);
  1199.  
  1200.                 if(From_CLI)
  1201.                     Printf("failed!\a\n");
  1202.  
  1203.                 exit(RETURN_FAIL);
  1204.             }
  1205.  
  1206.             if(!(MSeg -> DefaultKeyMap = (struct KeyMap *)AllocPub(sizeof(struct KeyMap))))
  1207.                 goto Failed;
  1208.  
  1209.             if(!(MSeg -> Segment = LoadSeg("KeyMacro-Handler")))
  1210.                 MSeg -> Segment = LoadSeg("L:KeyMacro-Handler");
  1211.  
  1212.             if(!MSeg -> Segment)
  1213.             {
  1214.                 if(From_CLI)
  1215.                     Printf("unable to find \33[33mL:KeyMacro-Handler\33[31m\a!\n");
  1216.  
  1217.                 FreeRem(MSeg -> DefaultKeyMap);
  1218.                 FreeRem(MSeg -> Port . mp_Node . ln_Name);
  1219.                 FreeRem(MSeg);
  1220.  
  1221.                 exit(RETURN_FAIL);
  1222.             }
  1223.             else
  1224.             {
  1225.                 AddPort(&MSeg -> Port);
  1226.  
  1227.                 if(!CreateProc("KeyMacro-Handler",10,MSeg -> Segment,4096))
  1228.                     goto NoMem;
  1229.  
  1230.                 Wait(SIGBREAKF_CTRL_C);
  1231.  
  1232.                 if(!MSeg -> Child)
  1233.                 {
  1234. NoMem:                    if(From_CLI)
  1235.                         Printf("\33[33mFAILED!\33[31m (care to retry?)\n");
  1236.  
  1237.                     RemPort(&MSeg -> Port);
  1238.  
  1239.                     FreeRem(MSeg -> DefaultKeyMap);
  1240.                     FreeRem(MSeg -> Port . mp_Node . ln_Name);
  1241.  
  1242.                     if(MSeg -> Segment)
  1243.                         UnLoadSeg(MSeg -> Segment);
  1244.  
  1245.                     FreeRem(MSeg);
  1246.  
  1247.                     exit(RETURN_FAIL);
  1248.                 }
  1249.                 else
  1250.                 {
  1251.                     if(From_CLI)
  1252.                         Printf("initializing, ");
  1253.  
  1254.                     GetDefaultKeyMap();
  1255.  
  1256.                     if(From_CLI)
  1257.                         Puts("Okay.");
  1258.                     else
  1259.                         SimpleRequest("\33[1mKeyMacro\33[0m installed.");
  1260.  
  1261.                     Created = TRUE;
  1262.                 }
  1263.             }
  1264.         }
  1265.     }
  1266.  
  1267.     if(argv[ARG_DELAY])
  1268.     {
  1269.         LONG Value = Atol(argv[ARG_DELAY]);
  1270.  
  1271.         if(Value)
  1272.         {
  1273.             if(Value < 10000)
  1274.             {
  1275.                 if(From_CLI)
  1276.                     Printf("\33[1mKeyMacro:\33[0m Delay value too small - must be >= 10000!\n");
  1277.  
  1278.                 exit(RETURN_ERROR);
  1279.             }
  1280.         }
  1281.  
  1282.         MSeg -> Delay = Value;
  1283.     }
  1284.  
  1285.         /* Update the macro key list. */
  1286.  
  1287.     if(!Created && From_CLI)
  1288.     {
  1289.         Printf("\33[1mKeyMacro:\33[0m Updating macro keys... ");
  1290.  
  1291.         if(!UpdateList(FileName))
  1292.         {
  1293.             Printf("FAILED!\a\n");
  1294.             exit(RETURN_ERROR);
  1295.         }
  1296.         else
  1297.             Printf("Done.\n");
  1298.     }
  1299.     else
  1300.     {
  1301.         if(!UpdateList(FileName))
  1302.             exit(RETURN_ERROR);
  1303.     }
  1304.  
  1305.     exit(RETURN_OK);
  1306. }
  1307.